///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_FORMAT_H_
#define _BUOLA_IMAGE_FORMAT_H_

#include <buola/image.h>
#include <buola/image/ccolorspaceconversion.h>
#include <buola/image/cimage.h>
#include <buola/image/ccolor.h>
#include <buola/image/adaptors.h>

namespace buola { namespace img {

#define DECLARE_IMG_FORMAT(name,colorspace,channel,id)                                                              \
    struct TFormat_##name                                                                                           \
    {                                                                                                               \
        static const EImageFormat mID=id;                                                                                 \
        typedef colorspace TColorSpace;                                                                             \
        typedef channel TChannel;                                                                                   \
        static const std::size_t mPixelSize=TColorSpace::cChannels*sizeof(typename TChannel::TType);                \
    }
    
#define DECLARE_IMG_TYPES(name)                                                                                     \
    typedef CImage<TFormat_##name> CImage_##name;                                                                   \
    typedef CPixel<TFormat_##name> CPixel_##name;                                                                   \
    typedef CView<TFormat_##name> CView_##name;                                                                     \
    typedef CMView<TFormat_##name> CMView_##name

#define DECLARE_IMG_FUNCTIONS(name)                                                                                 \
    template<typename... tArgs>                                                                                     \
    inline CView<TFormat_##name> view_##name(tArgs&&... pArgs)                                                      \
    {                                                                                                               \
        return CView<TFormat_##name>(std::forward<tArgs>(pArgs)...);                                                \
    }                                                                                                               \
    template<typename... tArgs>                                                                                     \
    inline CMView<TFormat_##name> mview_##name(tArgs&&... pArgs)                                                    \
    {                                                                                                               \
        return CMView<TFormat_##name>(std::forward<tArgs>(pArgs)...);                                               \
    }

#define CREATE_IMG_FORMAT(colorspace,channel,id)                                                                    \
    DECLARE_IMG_FORMAT(colorspace##channel,TColorSpace_##colorspace,TChannel_##channel,id);                         \
    DECLARE_IMG_FUNCTIONS(colorspace##channel)                                                                      \
    DECLARE_IMG_TYPES(colorspace##channel)

enum EImageFormat
{
    FORMAT_INVALID=-1,
    FORMAT_ANY=0,
    FORMAT_RGB8,
    FORMAT_RGBA8,
    FORMAT_BGR8,
    FORMAT_BGRA8,
    FORMAT_GRAY8,
    FORMAT_RGB16,
    FORMAT_RGBA16,
    FORMAT_GRAY16,
    FORMAT_GRAY16S,
    FORMAT_RGB32,
    FORMAT_RGBA32,
    FORMAT_GRAY32,
    FORMAT_GRAY32S,
    FORMAT_XY32S,
    FORMAT_XYZ32S,
    FORMAT_RGB32F,
    FORMAT_RGBA32F,
    FORMAT_GRAY32F,
    FORMAT_HSV32F,
    FORMAT_XY32F,
    FORMAT_XYZ32F,
    FORMAT_XYZ64F,
    FORMAT_GRAY64F,
    FORMAT_POINT_FLOAT_OFFSET=0x1000,
    FORMAT_POINT_DOUBLE_OFFSET=0x2000,
    FORMAT_POINT_NORMAL_FLOAT_OFFSET=0x3000,
    FORMAT_POINT_NORMAL_DOUBLE_OFFSET=0x4000,
    FORMAT_POINT_RGB8=FORMAT_POINT_FLOAT_OFFSET+FORMAT_RGB8
};
    
CREATE_IMG_FORMAT(rgb,8,FORMAT_RGB8);
CREATE_IMG_FORMAT(rgba,8,FORMAT_RGBA8);
CREATE_IMG_FORMAT(bgr,8,FORMAT_BGR8);
CREATE_IMG_FORMAT(bgra,8,FORMAT_BGRA8);
CREATE_IMG_FORMAT(gray,8,FORMAT_GRAY8);
CREATE_IMG_FORMAT(rgb,16,FORMAT_RGB16);
CREATE_IMG_FORMAT(rgba,16,FORMAT_RGBA16);
CREATE_IMG_FORMAT(gray,16,FORMAT_GRAY16);
CREATE_IMG_FORMAT(gray,16s,FORMAT_GRAY16S);
CREATE_IMG_FORMAT(rgb,32,FORMAT_RGB32);
CREATE_IMG_FORMAT(rgba,32,FORMAT_RGBA32);
CREATE_IMG_FORMAT(gray,32,FORMAT_GRAY32);
CREATE_IMG_FORMAT(gray,32s,FORMAT_GRAY32S);
CREATE_IMG_FORMAT(xy,32s,FORMAT_XY32S);
CREATE_IMG_FORMAT(xyz,32s,FORMAT_XYZ32S);
CREATE_IMG_FORMAT(rgb,32f,FORMAT_RGB32F);
CREATE_IMG_FORMAT(rgba,32f,FORMAT_RGBA32F);
CREATE_IMG_FORMAT(gray,32f,FORMAT_GRAY32F);
CREATE_IMG_FORMAT(hsv,32f,FORMAT_HSV32F);
CREATE_IMG_FORMAT(xy,32f,FORMAT_XY32F);
CREATE_IMG_FORMAT(xyz,32f,FORMAT_XYZ32F);
CREATE_IMG_FORMAT(xyz,64f,FORMAT_XYZ64F);
CREATE_IMG_FORMAT(gray,64f,FORMAT_GRAY64F);

template<typename tFormat>
CPixel<tFormat>::CPixel(const CColor &pColor)
{
    CPixel_rgba32f lColor(pColor.r,pColor.g,pColor.b,pColor.a);
    convert_pixel(lColor,*this);
}

/*namespace image*/ } /*namespace buola*/ }

#endif
